#include "bulk_storage.h"
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
int test(struct store * store);
int test2(struct store * store);
int test3(struct store * s);
int main() {
  struct store * store;
  /*store = store_open_memory(sizeof(int), 32);
  test(store);
  store_close(store);

  store = store_open_cached("gen_test", "gen_test.fat", sizeof(int), 32, 100);
  test(store);
  store_close(store);
  */
  /*cs = cs_open("cs_big", "cs_big.fat", sizeof(int[30]), 128, 10000);*/
  
  /*  store = store_open_memory(sizeof(int[30]), 128);
  //  test2(store);
  store_close(store);*/

  /*  store = store_open_cached("gen_big2", "gen_big2.fat", sizeof(int[30]), 128, 100);
  test2(store);
  store_close(store);
  */
  /*  store = store_open_memory(sizeof(int), 128);
  test3(store);
  store_close(store); */

  store = store_open_cached("rand", "rand.fat", sizeof(int), 128, 100);
  test3(store);
  cs_print(store->store_p);
  store_close(store);

  return 0;

}

int test(struct store * store) {
  int block, block2;
  int x = 42;
  int *y;

  block2 = store_new(store);
  block  = store_new(store);

  y = store_read(store, block);
  *y = 1;
  y = store_read(store, block2);
  *y = 2;

  x = -1;

  store_write(store, block);
  store_write(store, block2);

  y = store_read(store, block);
  assert(*y == 1);
  y = store_read(store, block2);
  assert(*y == 2);
  x = *y;
  printf("Block %d contains %d Other block is %d\n", block, x, block2);
  
  store_release(store, block);
  store_release(store, block2);
  return 0;

}

int test2(struct store * store) {
  off_t i;
  printf("That was fun, now some performance evaluations.\nCreate 1,000,000 int[30] blocks sequentially:\n");

  /*cs = cs_open("cs_big", "cs_big.fat", sizeof(int[30]), 128, 10000);*/


  for(i = 0; i < 1000000; i++) {
    off_t blockIdx = store_new(store); /*cs_newBlock(cs);*/
    int * block = store_read(store, blockIdx); /*cs_readBlock(cs, blockIdx);*/
    int j;
    debug(TRIVIAL, ("cs_newBlock:\t%ld\t", (long)blockIdx));


    for(j = 0; j < 30; j++) {
      block[j] = blockIdx;
    } 
    /*    cs_writeBlock(cs, blockIdx); */
    store_write(store, blockIdx);
    store_release(store, blockIdx);

    //    debug(TRIVIAL, (" %x\n", (unsigned int)store_read(store, blockIdx)));
    if(i && ! (i % 100000)) {
      debug(INFO, ("  %d00,000\n", (int)i/100000));
      //      cs_freeBlock(cs, blockIdx);
      //  store_free(store, blockIdx);
    }
  }

  printf("1,000,000\n");

  printf("Reading blocks back in...");
  for(i = 0; i < 1000000; i++) {
    int * ptr = store_read(store, i);
    int j;
    for(j = 0; j < 30; j++) {
      //    printf("%d\n", j);
      assert(j > -1 && j < 30);
      assert(ptr[j] == i);
    }
    
    //    debug(TRIVIAL, (" %x\n", (unsigned int)store_read(store, i)));
    if(i && ! (i % 100000)) {
      debug(INFO, ("  %d00,000\n", (int)i/100000));
      //      cs_freeBlock(cs, blockIdx);
      store_free(store, i);
    }
    
    store_release(store, i);
    //  cs_close(cs);
  }
  printf("Done\n");
  return 0;
}

#define SIZE3 600
#define SPIN3 2
#define RUNS3 10000000

int test3(struct store * s) {
  int requests[SIZE3];
  int request_spinner[SPIN3];
  
  int i;

  for(i = 0; i < SPIN3; i++) {
    request_spinner[i] = -1;
  }
  
  for(i = 0; i < SIZE3; i++) {
    int * j;
    int k;
    k = store_new(s);
    j = (int*)store_read(s, k);
    *j = k;
    requests[i] = k;
    store_write(s, k);
    store_release(s, k);
  }
  
  for(i = 0; i < RUNS3; i++) {
    int * j;
    /*   if(request_spinner[(i+1) % SPIN3] != -1) {
      store_release(s, request_spinner[(i+1) % SPIN3]);
      }*/
  
    request_spinner[i % SPIN3] = requests[(int)(((float)SIZE3-1) * rand() / RAND_MAX+1.0)];
    j = store_read(s, request_spinner[i % SPIN3]);
    //    printf("%d\n", request_spinner[i%SPIN3]);
    assert(*j == request_spinner[i % SPIN3]);

    store_write(s,  request_spinner[i % SPIN3]);
    store_release(s, request_spinner[i % SPIN3]);
    /* if(!(i %SIZE3)) {
      printf(".");
      }*/
    //    printf("%d ", i);
  }
  return 0;
}
